// RUN: circt-opt --pass-pipeline='builtin.module(ibis-add-operator-library, ibis.design(ibis.class(ibis.method.df(ibis.sblock.isolated(pipeline-schedule-linear)))))' %s | \
// RUN:   FileCheck %s

// CHECK-LABEL:   ssp.library @ibis_operator_library {
// CHECK:           operator_type @comb.add [latency<1>]
// CHECK:           operator_type @comb.sub [latency<1>]
// CHECK:           operator_type @comb.mul [latency<2>]
// CHECK:           operator_type @comb.mods [latency<2>]
// CHECK:           operator_type @comb.modu [latency<2>]
// CHECK:           operator_type @comb.and [latency<0>]
// CHECK:           operator_type @comb.or [latency<0>]
// CHECK:           operator_type @comb.xor [latency<0>]
// CHECK:           operator_type @comb.icmp [latency<1>]
// CHECK:           operator_type @comb.shl [latency<0>]
// CHECK:           operator_type @comb.shru [latency<0>]
// CHECK:           operator_type @comb.shrs [latency<1>]
// CHECK:         }

// CHECK-LABEL:   ibis.class sym @SchedulePipeline {
// CHECK:           %[[VAL_0:.*]] = ibis.this <@foo::@SchedulePipeline>
// CHECK:           ibis.method.df @foo(%[[VAL_1:.*]]: i32, %[[VAL_2:.*]]: i32) -> i32 {
// CHECK:             %[[VAL_3:.*]] = ibis.sblock.isolated (%[[VAL_4:.*]] : i32 = %[[VAL_1]], %[[VAL_5:.*]] : i32 = %[[VAL_2]]) -> i32 {
// CHECK:               %[[VAL_6:.*]], %[[VAL_7:.*]], %[[VAL_8:.*]], %[[VAL_9:.*]] = ibis.pipeline.header
// CHECK:               %[[VAL_10:.*]], %[[VAL_11:.*]] = pipeline.scheduled(%[[VAL_12:.*]] : i32 = %[[VAL_4]], %[[VAL_13:.*]] : i32 = %[[VAL_5]]) stall(%[[VAL_9]]) clock(%[[VAL_6]]) reset(%[[VAL_7]]) go(%[[VAL_8]]) entryEn(%[[VAL_14:.*]])  -> (out0 : i32) {
// CHECK:                 %[[VAL_15:.*]] = comb.mul %[[VAL_12]], %[[VAL_13]] {ssp.operator_type = @comb.mul} : i32
// CHECK:                 pipeline.stage ^bb1
// CHECK:               ^bb1(%[[VAL_16:.*]]: i1):
// CHECK:                 %[[VAL_17:.*]] = comb.add %[[VAL_12]], %[[VAL_13]] {ssp.operator_type = @comb.add} : i32
// CHECK:                 pipeline.stage ^bb2
// CHECK:               ^bb2(%[[VAL_18:.*]]: i1):
// CHECK:                 %[[VAL_19:.*]] = comb.sub %[[VAL_17]], %[[VAL_15]] {ssp.operator_type = @comb.sub} : i32
// CHECK:                 pipeline.stage ^bb3
// CHECK:               ^bb3(%[[VAL_20:.*]]: i1):
// CHECK:                 %[[VAL_21:.*]] = comb.mul %[[VAL_19]], %[[VAL_17]] {ssp.operator_type = @comb.mul} : i32
// CHECK:                 pipeline.stage ^bb4
// CHECK:               ^bb4(%[[VAL_22:.*]]: i1):
// CHECK:                 pipeline.stage ^bb5
// CHECK:               ^bb5(%[[VAL_23:.*]]: i1):
// CHECK:                 pipeline.return %[[VAL_21]] : i32
// CHECK:               }
// CHECK:               ibis.sblock.return %[[VAL_24:.*]] : i32
// CHECK:             }
// CHECK:             ibis.return %[[VAL_3]] : i32
// CHECK:           }
// CHECK:         }

ibis.design @foo {
ibis.class sym @SchedulePipeline {
  %this = ibis.this <@foo::@SchedulePipeline>
  // A test wherein the returned values are either a value generated by an
  // operation in the pipeline, or a value that's passed through the pipeline.
  // The resulting IR should have all values passing through the newly created
  // pipeline.
  ibis.method.df @foo(%a: i32, %b: i32) -> (i32) {
    %0 = ibis.sblock.isolated (%arg2 : i32 = %a, %arg3 : i32 = %b) -> i32 {
      %clock, %reset, %go, %stall = ibis.pipeline.header
      %out0, %done = pipeline.unscheduled(%in0 : i32 = %arg2, %in1 : i32 = %arg3) stall(%stall) clock(%clock) reset(%reset) go(%go) entryEn(%s0_enable)  {operator_lib = @ibis_operator_library} -> (out0 : i32) {
        %1 = comb.add %in0, %in1 {ssp.operator_type = @comb.add} : i32
        %2 = comb.mul %in0, %in1 {ssp.operator_type = @comb.mul} : i32
        %3 = comb.sub %1, %2 {ssp.operator_type = @comb.sub} : i32
        %4 = comb.mul %3, %1 {ssp.operator_type = @comb.mul} : i32
        pipeline.return %4 : i32
      }
      ibis.sblock.return %out0 : i32
    }
    ibis.return %0 : i32
  }
}
}
